package com.letu.core.dynamic;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 动态代理
 * by ligang
 * 2020-03-20
 */
public class DynamicProxy {

    //调用vo实体 set方法，参数传null
    public static void voInvokSetByField(Field field, Object object) {
        try {
            if ("serialVersionUID".equals(field.getName())) {
                return;
            }
            //enum类不处理
            try{
                if("java.lang.Enum".equals(field.getType().getSuperclass().getName())){
                    return;
                }
            }catch (Exception e){

            }



            Class fieldclass = FieldTypeUtil.getClassByFidldType(field.getType());
            Method m = object.getClass().getMethod(assembleSetMethod(fieldclass, field), fieldclass);
            Object[] obj = new Object[1];
            assembleDataNull(fieldclass, obj);
            m.invoke(object, obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //调用vo实体 set方法，参数传非空
    public static void voInvokSetNotNullByField(Field field, Object object) {
        try {
            if ("serialVersionUID".equals(field.getName())) {
                return;
            }
            //enum类不处理
            try{
                if("java.lang.Enum".equals(field.getType().getSuperclass().getName())){
                    return;
                }
            }catch (Exception e){

            }
            //查询是否是空
            Class fieldclass = FieldTypeUtil.getClassByFidldType(field.getType());
            Method m = object.getClass().getMethod(assembleGetMethod(fieldclass, field));
            Object invoke = m.invoke(object);
            if(invoke==null){
                //null则给默认值
                m = object.getClass().getMethod(assembleSetMethod(fieldclass, field), fieldclass);
                Object[] obj = new Object[1];
                assembleDataNoNull(fieldclass, obj);
                m.invoke(object, obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 组装set方法名
     */
    public static String assembleSetMethod(Class fieldclass, Field field) {
        char[] chars = field.getName().toCharArray();
        if (fieldclass == boolean.class) {
            if (chars[0] == 'i' && chars[1] == 's' && Character.isUpperCase(chars[2])) {
                return "set" + field.getName().substring(2, field.getName().length());
            }
        }
        //特殊情况
        /**
         * 1、如果属性名的第二个字母大写，那么该属性名直接用作 getter/setter 方法中 get/set 的后部分，就是说大小写不变。例如属性名为uName，方法是getuName/setuName。
         *
         * 2、如果属性名的前两个字母是大写（一般的专有名词和缩略词都会大写），也是属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为URL，方法是getURL/setURL。
         *
         * 3、如果属性名的首字母大写，也是属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为Name，方法是getName/setName，这种是最糟糕的情况，会找不到属性出错，因为默认的属性名是name。
         *
         * 4、如果属性名以"is"开头，则getter方法会省掉get，set方法会去掉is。例如属性名为isOK，方法是isOK/setOK。
         */

        //情况1：第一个字符小写，第二个字符大写
        if (Character.isLowerCase(chars[0]) && Character.isUpperCase(chars[1])) {
            return "set" + strFirstCapital(field.getName());
        }
        //情况2：第一个字符大写，第二个字符大写
        if (Character.isLowerCase(chars[0]) && Character.isUpperCase(chars[1])) {
            return "set" + field.getName();
        }

        return "set" + strFirstCapital(field.getName());
    }

    /**
     * 组装清空null数据
     */
    public static Object[] assembleDataNull(Class fieldclass, Object[] obj) {
        if (fieldclass == int.class) {
            obj[0] = 0;
        } else if (fieldclass == double.class) {
            Double double1 = new Double(0);
            obj[0] = double1.doubleValue();
        } else if (fieldclass == long.class) {
            obj[0] = 0L;
        } else if (fieldclass == float.class) {
            obj[0] = 0f;
        } else if (fieldclass == Float.class) {
            obj[0] = 0f;
        } else if (fieldclass == boolean.class) {
            obj[0] = false;
        } else if (fieldclass == byte.class) {
            obj[0] = (byte) 0;
        } else if (fieldclass == Byte.class) {
            obj[0] = (byte) 0;
        }
        return obj;
    }


    /**
     * 组装设置有值数据
     */
    public static Object[] assembleDataNoNull(Class fieldclass, Object[] obj) {
        if (fieldclass == int.class) {
            obj[0] = 0;
        } else if (fieldclass == double.class) {
            Double double1 = new Double(0);
            obj[0] = double1.doubleValue();
        } else if (fieldclass == long.class) {
            obj[0] = 0L;
        } else if (fieldclass == float.class) {
            obj[0] = 0f;
        } else if (fieldclass == Float.class) {
            obj[0] = 0f;
        } else if (fieldclass == boolean.class) {
            obj[0] = false;
        } else if (fieldclass == byte.class) {
            obj[0] = (byte) 0;
        } else if (fieldclass == Byte.class) {
            obj[0] = 0;
        }else if (fieldclass == String.class) {
            obj[0] = new String();
        }else if (fieldclass == Integer.class) {
            obj[0] = new Integer(0);
        }else if (fieldclass == Double.class) {
            obj[0] = new Double(0);
        }else if (fieldclass == Long.class) {
            obj[0] = new Long(0);
        }else if (fieldclass == Boolean.class) {
            obj[0] = new Boolean(false);
        }else{
            Class classObject = FieldTypeUtil.getClassByBusinList(fieldclass);
            if(classObject!=null){
                try {
                    obj[0] =classObject.newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return obj;
    }

    //调用vo实体 set方法，参数传null
    public static void voInvokSetByField(Field field, Object object, Object data) {
        try {
            Method m = object.getClass().getMethod("set" + strFirstCapital(field.getName()), FieldTypeUtil.getClassByFidldType(field.getType()));
            Object[] obj = new Object[1];
            obj[0] = data;
            m.invoke(object, obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Object voInvokGetlByField(Field field, Object object) {
        try {
            if ("serialVersionUID".equals(field.getName())) {
                return null;
            }
            Method m = object.getClass().getMethod(assembleGetMethod(field.getClass(), field));
            Object invoke = m.invoke(object);
            return invoke;
        } catch (Exception e) {
//            e.printStackTrace();
        }
        return null;
    }

    /**
     * 组装set方法名
     */
    public static String assembleGetMethod(Class fieldclass, Field field) {
        char[] chars = field.getName().toCharArray();
        if (fieldclass == boolean.class) {
            String methodName = "is" + strFirstCapital(field.getName());
            if (chars[0] == 'i' && chars[1] == 's' && Character.isUpperCase(chars[2])) {
                return "is" + field.getName().substring(2, field.getName().length());
            }
        }

        //特殊情况
        /**
         * 1、如果属性名的第二个字母大写，那么该属性名直接用作 getter/setter 方法中 get/set 的后部分，就是说大小写不变。例如属性名为uName，方法是getuName/setuName。
         *
         * 2、如果属性名的前两个字母是大写（一般的专有名词和缩略词都会大写），也是属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为URL，方法是getURL/setURL。
         *
         * 3、如果属性名的首字母大写，也是属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为Name，方法是getName/setName，这种是最糟糕的情况，会找不到属性出错，因为默认的属性名是name。
         *
         * 4、如果属性名以"is"开头，则getter方法会省掉get，set方法会去掉is。例如属性名为isOK，方法是isOK/setOK。
         */

        //情况1：第一个字符小写，第二个字符大写
        if (Character.isLowerCase(chars[0]) && Character.isUpperCase(chars[1])) {
            return "get" + strFirstCapital(field.getName());
        }
        //情况2：第一个字符大写，第二个字符大写
        if (Character.isLowerCase(chars[0]) && Character.isUpperCase(chars[1])) {
            return "get" + field.getName();
        }

        return "get" + strFirstCapital(field.getName());
    }

    /**
     * 首字母大写
     *
     * @param str
     * @return
     */
    public static String strFirstCapital(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
    }

    /**
     * 第二个字母大写
     *
     * @param str
     * @return
     */
    public static String strSecondCapital(String str) {
        return str.substring(0, 1) + str.substring(1, 2).toUpperCase() + str.substring(2);
    }
}
